package App.Service;

import App.Conflict.Constant;
import App.Entity.*;
import App.Repository.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * Created by yu on 2017/7/20.
 */
@Service
public class ProjectService
{
    @Autowired
    ProjectRepository projectRepository;
    @Autowired
    ProjectCheckRepository checkRepository;
    @Autowired
    TaskRepository taskRepository;
    @Autowired
    PersonRepository personRepository;
    @Autowired
    TaskCheckRepository taskCheckRepository;
    @Autowired
    NoticeRepository noticeRepository;
    @Autowired
    NoticeCheckRepository noticeCheckRepository;
    @Autowired
    ContactCheckRepository contactCheckRepository;

   //创建项目
    public Project createProject(Project project)
    {
        project.setPublicTime(System.currentTimeMillis());
        project.setStatus(Project.Running);
        projectRepository.save(project);
        ProjectCheck check=new ProjectCheck();
        check.setAuthId(project.getPublisher());
        check.setProjectId(project.getId());
        checkRepository.save(check);
        return project;
    }

    //完成项目
    public Project finishProject(Long ProjectId){
        Project project=projectRepository.findOne(ProjectId);
        if(project!=null){
            project.setStatus(Project.Finish);
            projectRepository.save(project);
        }
        return project;
    }



    //添加联系人到项目中
    public void addPersonToProject(ProjectCheck projectCheck)
    {
        Long authId=projectCheck.getAuthId();
        List<Long>noticeIds=noticeRepository.getNoticeIdsByProjectId(projectCheck.getProjectId());
        List<NoticeCheck>checks=noticeIds.stream().map(id->{
            NoticeCheck check=new NoticeCheck();
            check.setProjectId(projectCheck.getProjectId());
            check.setStatus(NoticeCheck.Read);
            check.setReceiverId(authId);
            check.setNoticeId(id);
            return check;
        }).collect(Collectors.toList());
        noticeCheckRepository.save(checks);
        checkRepository.save(projectCheck);
    }

    public void addPeopleToProject(Iterable<ProjectCheck> projectChecks)
    {
        checkRepository.save(projectChecks);
    }

    //获取某人的所有项目
    public List<Project> getOwnProjects(long authId)
    {
        return (List<Project>) projectRepository.findAll(checkRepository.getProjectIdsByAuthId(authId));
    }

    //为项目添加任务
    public void addTask(Task task)
    {
        task.setPublicTime(System.currentTimeMillis());
        taskRepository.save(task);
    }

    //判断有无权限添加任务
    public boolean canAddTask(Long projectId,Long AuthId)
    {
        return true;
    }

    //判断项目是否存在
    public boolean existProject(Long projectId)
    {
        return projectRepository.exists(projectId);
    }

    public void joinProject(Long projectId,Long AuthId)
    {
        checkRepository.save(new ProjectCheck(AuthId,projectId));
    }

    //判断该成员是否在项目中
    public boolean inProject(Long ProjectId,Long AuthId)
    {
        return (checkRepository.getIdByAuthIdAndProjectId(AuthId,ProjectId)!=null);
    }

    //判断任务是否可以被领取
    public boolean waitForReceive(Long TaskId)
    {
        return !taskRepository.findOne(TaskId).hasReceive();
    }

    //完成任务
    public void finishTask(Long TaskId,Long AuthId)
    {
        TaskReceive check=taskCheckRepository.findByTaskIdAndReceiverId(TaskId, AuthId);
        check.setStatus(TaskReceive.Finish);
        taskCheckRepository.save(check);
        //taskCheckRepository.setTaskStatusByTaskIdAndReceiverId(TaskId,AuthId,TaskReceive.Finish);
    }

    //取消完成任务
    public void cancelFinishTask(Long TaskId,Long AuthId)
    {
        TaskReceive check=taskCheckRepository.findByTaskIdAndReceiverId(TaskId, AuthId);
        check.setStatus(TaskReceive.Running);
        taskCheckRepository.save(check);
        //taskCheckRepository.setTaskStatusByTaskIdAndReceiverId(TaskId,AuthId,TaskReceive.Running);
    }

    //获取项目的所有任务
    public List<Task> getTask(long projectId)
    {
        return taskRepository.getTasksByProjectIdOrderByPublicTimeDesc(projectId);
    }

    //获得项目中的所有成员
    public List<Person> getProjectMates(long projectId)
    {
        List<Long> ids=checkRepository.getPeopleIdsByProjectId(projectId);
        System.out.println(ids);
        return (List<Person>) personRepository.findPeopleByAuthIdIn(checkRepository.getPeopleIdsByProjectId(projectId));
    }

    //在添加成员的时候，返回个人的联系人
    public List<Map<String,Object>> getProjectContact(long projectId,long authId){
        List<Long> ids=checkRepository.getPeopleIdsByProjectId(projectId);
        Set<Long> idSet=new HashSet<>(ids);
        List<ContactCheck>checks=contactCheckRepository.findContactChecksByOwnerIdOrderByAddTimeDesc(authId);
        return checks.stream().map(check->{
            Person person=personRepository.findFirstByAuthId(check.getContactId());
            if(person==null) return null;
            Map<String,Object>res=person.toMap();
            if(idSet.contains(check.getContactId())){
                res.put("inProject",true);
                return res;
            }
            res.put("inProject",false);
            return res;
        }).filter(Objects::nonNull).collect(Collectors.toList());




    }

    //某个成员领取任务
    public void giveTask(long taskId,long authId,long projectId)
    {
        Task task=taskRepository.findOne(taskId);
        if(task!=null)
        {
            //标记已经领取了
            task.setReceive();
        }
        TaskReceive taskReceive=new TaskReceive(authId,taskId,projectId,TaskReceive.Running,System.currentTimeMillis());
        taskCheckRepository.save(taskReceive);
    }

    //获得某个成员在某项目中的任务
    public List<Task> getPersonTask(long projectId,long authId)
    {
        List<Long>taskIds=taskCheckRepository.getTaskIdByProjectIdAndReceiverId(projectId,authId);
        List<Task> tasks= (List<Task>) taskRepository.findAll(taskIds);
        return tasks;
    }

    //获取某个成员在某项目中正在进行的任务
    public List<Task> getPersonRunningTask(long projectId,long authId)
    {
        List<Long> taskIds=taskCheckRepository.getTaskIdsByProjectIdAndReceiverIdAndStatus(projectId,authId,TaskReceive.Running);
        return (List<Task>) taskRepository.findAll(taskIds);
    }

    //获取某个成员在某项目中完成的任务
    public List<Task> getPersonFinishedTask(long projectId,long authId)
    {
        List<Long> taskIds=taskCheckRepository.getTaskIdsByProjectIdAndReceiverIdAndStatus(projectId,authId,TaskReceive.Finish);
        return (List<Task>) taskRepository.findAll(taskIds);
    }

    public List<Map<String,Object>> getMatesWithProgress(Long ProjectId)
    {
        List<Person> mates=getProjectMates(ProjectId);
        return mates.stream().filter(Objects::nonNull).map(mate->{
            Map<String,Object> res=mate.toMap();
            Long finishedCount=taskCheckRepository.getTasksCountByAuthIdAndProjectIdAndStatus(ProjectId,mate.getAuthId(),TaskReceive.Finish);
            Long runningCount=taskCheckRepository.getTasksCountByAuthIdAndProjectIdAndStatus(ProjectId,mate.getAuthId(),TaskReceive.Running);
            res.put("finishedCount",finishedCount);
            res.put("runningCount",runningCount);
            res.put("allCount",runningCount+finishedCount);
            return res;
        }).collect(Collectors.toList());
    }

    //发布通知
    public void publishNotice(Notice notice){
        Long projectId=notice.getProjectId();
        if(projectId==null||projectId<0) return;
        notice.setPublicTime(System.currentTimeMillis());
        noticeRepository.save(notice);
        List<Long> mates=checkRepository.getPeopleIdsByProjectId(projectId);
        List<NoticeCheck> checks=mates.stream().map((personId)->{
            NoticeCheck check=new NoticeCheck();
            check.setNoticeId(notice.getId());
            check.setProjectId(notice.getProjectId());
            check.setReceiverId(personId);
            check.setPublicTime(notice.getPublicTime());
            check.setStatus(NoticeCheck.NotRead);
            return check;
        }).collect(Collectors.toList());
        noticeCheckRepository.save(checks);
    }

    //获取项目的进度
    public Object getProgressOfProject(long projectId)
    {
        Map<String,Long> res=new HashMap<>(2);
        res.put("finished", taskCheckRepository.getFinishTaskCountByProjectId(projectId));
        res.put("amount",taskRepository.getTaskCountByProjectId(projectId));
        return res;
    }

    //获得项目中所有正在进行的任务
    public List<Map<String,Object>> getRunningTaskOfProject(long projectId){
        List<TaskReceive> checks=taskCheckRepository.findByProjectIdAndStatusOrderByModifyTimeDesc(projectId,TaskReceive.Running);
        return getTasksByTaskCheck(checks);
    }

    //获取项目中已经完成的项目
    public List<Map<String,Object>> getFinishTaskOfProject(long projectId){
        List<TaskReceive> checks=taskCheckRepository.findByProjectIdAndStatusOrderByModifyTimeDesc(projectId,TaskReceive.Finish);
        return getTasksByTaskCheck(checks);
    }

    //根据modifyTime分页获得项目中已经完成的项目，用于更新
    public List<Map<String,Object>> getFinishTaskOfProjectByPage(long projectId,long modifyTime){
        List<TaskReceive>checks=taskCheckRepository.findByProjectIdAndStatusAndModifyTimeLessThanOrderByModifyTimeDesc(projectId,TaskReceive.Finish,modifyTime,new PageRequest(0,6));
        return getTasksByTaskCheck(checks);
    }

    //根据modifyTime获得更新的task
    public List<Map<String,Object>> getUpdatedTaskByModifyTime(long projectId,long modifyTime){
        List<TaskReceive>checks=taskCheckRepository.findByProjectIdAndModifyTimeGreaterThanOrderByModifyTimeDesc(projectId, modifyTime);
        return getTasksByTaskCheck(checks);
    }

    public List<Task> getUpdatedReceivingTaskByPublicTime(long projectId,long publicTime){
        return taskRepository.findByProjectIdAndStatusAndPublicTimeGreaterThanOrderByPublicTimeDesc(projectId,Task.NotReceive,publicTime);
    }

    //将TaskCheck中的信息转化为对应的Task
    private List<Map<String,Object>> getTasksByTaskCheck(List<TaskReceive> checks){
        return checks.stream().map((check)->{
            Map<String,Object> res=null;
            Task task=taskRepository.findOne(check.getTaskId());
            Person person=personRepository.findFirstByAuthId(check.getReceiverId());
            if(task!=null){
                res=task.toMap();
                if(person!=null){
                    res.put("receiverName",person.getUsername());
                }
                res.put("receiverId",check.getReceiverId());
                res.put("modifyTime",check.getModifyTime());
                res.put("receiveStatus",check.getStatus());
            }
            return res;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }



    //获得项目中所有未领取的任务
    public List<Task> getReceiveTask(long projectId)
    {
        return taskRepository.getTasksByProjectIdAndStatusOrderByPublicTimeDesc(projectId,Task.NotReceive);
    }



    //获取个人在项目中的所有通知
    public List<Map<String,Object>> getNotices(long projectId,long authId){
       List<NoticeCheck> checks=noticeCheckRepository.findByReceiverIdAndProjectIdOrderByPublicTimeDesc(authId,projectId);
       return checks.parallelStream().map(check->{
           Map<String,Object> res=null;
           Notice notice=noticeRepository.findOne(check.getNoticeId());
           if(notice!=null){
               res=notice.toMap();
               String name="unknown";
               if(notice.getPublisher()!=null){
                   name=personRepository.getPersonNameByAuthId(notice.getPublisher());
               }
               res.put("read",check.getStatus()==NoticeCheck.Read);
               res.put("publisherName",name);
           }
           return res;
       }).filter(Objects::nonNull).collect(Collectors.toList());
    }

    //获得项目所有新通知
    public List<Map<String,Object>> getNewNotice(long projectId,long authId)
    {
        List<Long>ids=noticeCheckRepository.findNoticeIdByAuthIdAndProjectIdAndStatusOrderByPublicTimeDesc(authId,projectId,NoticeCheck.NotRead);
        List<Notice> notices=(List<Notice>)noticeRepository.findAll(ids);
        if(!notices.isEmpty())
        {
            return handleNotice(notices.stream());
        }
        return null;
    }

    //获得项目所有已读通知
    public List<Map<String,Object>> getReadNotice(long projectId,long authId)
    {
        List<Long>ids=noticeCheckRepository.findNoticeIdByAuthIdAndProjectIdAndStatusOrderByPublicTimeDesc(authId,projectId,NoticeCheck.Read);
        List<Notice> notices=(List<Notice>)noticeRepository.findAll(ids);
        if(!notices.isEmpty())
        {
            return handleNotice(notices.stream());
        }
        return null;

    }

    public List<Map<String,Object>> handleNotice(Stream<Notice> notices){
        return notices.filter(Objects::nonNull).map(notice->{
            String name=personRepository.getPersonNameByAuthId(notice.getPublisher());
            Map<String,Object> res=notice.toMap();
            res.put("publisherName",name);
            return res;
        }).collect(Collectors.toList());
    }

















}
